<template>
  <view class="mui-app-scaffold" :style="{ backgroundColor: appConfig.backgroundColor || '', ...themeStyle }">
    <template v-if="showNavigation && !useSystemNavigation">
      <slot name="navbar">
        <NavBar />
      </slot>
    </template>
    <view class="app-body-wrap"
          :class="{ 'page-animation': appConfigStore.pageAnimation, 'page-animation-loaded': appConfigStore.pageAnimation && isLoadPage }"
          :style="appBodyStyle"
    >
      <template v-if="pageStatus === 'normal'">
        <slot name="default" :app-config="appConfig">
        </slot>
      </template>
      <template v-else>
        <slot name="empty" :type="pageStatus">
          <Empty :type="pageStatus" @refresh="refresh" />
        </slot>
      </template>
      <view v-if="!isTabBar" class="fixed-footer fix-bot" :style="{ zIndex: fixedFooterZIndex }">
        <slot name="fixed-footer"></slot>
      </view>
    </view>
    <slot name="extra"></slot>
    <slot name="alert">
    </slot>
    <LayoutPopup v-model="defaultShow" :zoom="true" mode="center" :popup="false" :z-index="10019"
                 :mask-close-able="popupConfig.hideOnBlur" :negative-top="useSystemNavigation ? '100rpx' : ''"
                 @on-mask-click="onUiMaskClose"
    >
      <LayoutBasePopup :popup-config="popupConfig" @close="closeUiBox()" />
    </LayoutPopup>
    <LayoutPopup v-model="customShow" :zoom="true" :mode="customPopupConfig.mode" :popup="false" :z-index="10009"
                 :mask-close-able="customPopupConfig.hideOnBlur" :negative-top="useSystemNavigation ? '100rpx' : ''"
                 @on-mask-click="onCustomMaskClose"
    >
      <slot name="custom-popup" :custom-popup-config="customPopupConfig" :obj="customPopupConfig.obj"
            :list="customPopupConfig.list"
      ></slot>
    </LayoutPopup>
    <WaterMark v-if="appConfigStore.showMark" :watermark="appConfigStore.waterMarkText" />
    <Ui :text="ui.title" :icon="ui.icon" :mask="ui.mask" :show="ui.show" :mask-color="ui.maskColor" />
  </view>
</template>

<script lang="ts" setup>
import type { WinInfo } from '../components/lib/function'
import type { UniComponentInternalInstance } from './utils'

import { computed, getCurrentInstance, onMounted, ref, useSlots } from 'vue'

import { getWindow } from '../components/lib/function'
import useAppStore from '../manager/app'
import useThemeStore from '../manager/theme'
import LayoutBasePopup from './components/confirm-box/base.vue'
import LayoutPopup from './components/confirm-box/popup/index.vue'
import Empty from './components/empty/index.vue'

import NavBar from './components/nav-bar/nav-bar.vue'
import Ui from './components/ui/index.vue'

import WaterMark from './components/water-mark/index.vue'
import props from './props'
import useUi from './useUi'
import { findPageInstance } from './utils'
/**
 * 应用容器
 * @description 这是所有创建应用的最外层基础容器。
 */

const _props = defineProps(props)

const themeStore = useThemeStore()
const appConfigStore = useAppStore()
const ui = useUi()

const sysInfo = ref<WinInfo>(getWindow())
// 向所有子组件传递本次获取的系统信息，以减少频繁的请求.
// provide('systemInfo', sysInfo.value)
const themeStyle = computed(() => {
  const styleObj = themeStore.mapThemeVarsToCSSVars(_props.themeVars)
  return { ...themeStore.theme.style, ...styleObj }
})
const appConfig = computed(() => {
  /* 状态栏高度 */
  const statusBarHeight = sysInfo.value!.statusBarHeight || 0
  // 屏幕宽度
  const screenWidth = sysInfo.value!.screenWidth || 0
  // 屏幕高度
  const screenHeight = sysInfo.value!.screenHeight || 0
  // 视窗的宽。
  const view_width = sysInfo.value!.windowWidth || 0
  // 视窗的高度。
  const view_height = sysInfo.value!.windowHeight || 0

  const tabbarH = _props.isTabBar ? _props.tabbarHeight : 0

  /* 自定义导航栏高度 */
  let navigationH = statusBarHeight
  if (_props.showNavigation || _props.useSystemNavigation) {
    // 如果使用导航栏
    navigationH = _props.navigationHeight + statusBarHeight
  }

  // const appContentHeight = screenHeight - tabbarH - navigationH // 计算除了tabbar和顶部导航栏之外的内容高度,导航栏高度包含状态栏高度
  return {
    statusBarHeight,
    width: view_width,
    height: view_height,
    bgImg: _props.bgImg,
    screenWidth,
    screenHeight,
    navigationH,
    tabbarH,
    backgroundColor: _props.backgroundColor,
    appContentHeight: `calc(100vh - ${tabbarH}px - ${navigationH}px)`,
  }
})

const fixedAreaHeight = ref('0px')
const appBodyStyle = computed(() => {
  const p = uni.upx2px(Number(_props!.padding || 0))
  const style = {
    paddingLeft: `${p}px`,
    paddingRight: `${p}px`,
    paddingBottom: fixedAreaHeight.value,
    minHeight: appConfig.value.appContentHeight,
    background: '',
  }
  if (appConfig.value.bgImg) style.background = `url(${appConfig.value.bgImg})`
  return style
})

const $slots = useSlots()
const ins = getCurrentInstance()
function updateFixedArea() {
  if ($slots['fixed-footer']) {
    const query = uni.createSelectorQuery().in(ins?.proxy)
    query
      .select('.fixed-footer')
      .boundingClientRect((data: any) => {
        if (!data?.height) return
        fixedAreaHeight.value = `${data.height}px`
      })
      .exec()
  }
}

function refresh(e: any) {
  uni.$util.reloadPage()
}
// const confirmBoxRef = ref<InstanceType<typeof MuiConfirm> | null>(null)
const defaultShow = ref(false)
const popupConfig = ref<ConfirmBoxOptions>({})
interface ConfirmBoxOptions {
  title?: string
  content?: string
  showCancel?: boolean
  showConfirm?: boolean
  cancelText?: string
  cancelColor?: string
  confirmText?: string
  confirmColor?: string
  contentStyle?: Record<string, string> | string
  hideOnBlur?: boolean
  autoClose?: boolean
  cancelHandler?: (action: 'mask' | 'btn') => void
  confirmHandler?: () => void
}
function openUiBox({
  title = '温馨提示',
  content = '',
  contentStyle = 'font-size: 28rpx; color: #1a1a1a;',
  cancelColor = ui.popupConfig.cancelColor,
  confirmColor = ui.popupConfig.confirmColor,
  showCancel = true,
  showConfirm = true,
  cancelText = '取消',
  confirmText = '确认',
  hideOnBlur = false,
  autoClose = true,
  cancelHandler,
  confirmHandler,
}: ConfirmBoxOptions = {}) {
  popupConfig.value = {
    title,
    content,
    contentStyle,

    showCancel,
    showConfirm,

    cancelColor,
    confirmColor,
    cancelText,
    confirmText,
    hideOnBlur,
    autoClose,

    cancelHandler,
    confirmHandler,
  }
  defaultShow.value = true
}
function onUiMaskClose() {
  popupConfig.value.autoClose && closeUiBox()
  popupConfig.value.cancelHandler?.('mask')
}
function closeUiBox() {
  defaultShow.value = false
}
interface CustomPopupOptions<T extends Record<string, any> = any> {
  type?: string
  mode?: 'center' | 'bottom' | 'top' | 'left' | 'right'
  obj?: T
  list?: Array<T>
  autoClose?: boolean
  hideOnBlur?: boolean
  cancelHandler?: (action: 'mask' | 'btn') => void
  confirmHandler?: () => void
}
const customShow = ref(false)
const customPopupConfig = ref<CustomPopupOptions>({})

function openCustomUiBox({ type = '', autoClose, mode = 'center', obj = {}, list = [], hideOnBlur = false, cancelHandler, confirmHandler }: CustomPopupOptions = {}) {
  customPopupConfig.value = {
    type,
    obj,
    mode,
    list,
    autoClose,
    hideOnBlur,
    cancelHandler,
    confirmHandler,
  }
  customShow.value = true
}
function onCustomMaskClose() {
  customPopupConfig.value.autoClose && closeCustomUiBox()
  customPopupConfig.value.cancelHandler?.('mask')
}
function closeCustomUiBox() {
  customShow.value = false
}

type PageStatus = 'normal' | 'empty' | 'error' | 'search' | 'network'
const pageStatus = ref<PageStatus>('normal')
function setPageStatus(status: PageStatus) {
  pageStatus.value = status
}
// 扩展
const exposeFunc = {
  openUiBox,
  openCustomUiBox,
  closeCustomUiBox,
  updateFixedArea,
  setPageStatus
}

const page = findPageInstance(ins as UniComponentInternalInstance) // ins?.$pageInstance.ctx
if (page) {
  page.$$muiLayout = exposeFunc
}

const isLoadPage = ref(false)
onMounted(() => {
  updateFixedArea()
  isLoadPage.value = true
})
defineExpose(exposeFunc)
</script>

<script lang="ts">
export default {
  name: 'MuiConfigProvider',
  options: {
    // 将自定义节点设置成虚拟的，更加接近Vue组件的表现，能更好的使用flex属性
    virtualHost: true,
    addGlobalClass: true,
    styleIsolation: 'shared',
  },
}
</script>

<style scoped>
.mui-app-scaffold {
  display: flex;
  flex-direction: column;
}

.page-animation {
  /* opacity: 0; */
  filter: blur(7px);
  transition: all 0.5s ease;
  will-change: opacity, filter;
}

.page-animation-loaded {
  /* opacity: 1; */
  filter: none;
}

.app-body-wrap {
  display: flex;
  flex-direction: column;
  width: 750rpx;
}

.blur {
  backdrop-filter: blur(10px);
}

.fixed-footer {
  position: fixed;
  left: 0;
  bottom: 0;
  width: 750rpx;
  z-index: 1;
}

.fix-bot {
  box-sizing: content-box;
  padding-bottom: 0;
  padding-bottom: constant(safe-area-inset-bottom);
  padding-bottom: env(safe-area-inset-bottom);
}
</style>
